use std::fs;
use std::io::{Error, ErrorKind};
use std::path::Path;

pub struct VueModule {
    module_name: String,
    file_name: String,
    route_name: String,
}
pub fn get_file_names(dir_path: &Path) -> Result<Vec<String>, Error> {
    fs::read_dir(dir_path).and_then(|entries| {
        entries
            .into_iter()
            .filter(|entry| {
                entry
                    .as_ref()
                    .map(|_entry| _entry.path().is_file())
                    .unwrap_or_else(|_| false)
            })
            .map(|entry| {
                entry.and_then(|_entry| {
                    _entry
                        .path()
                        .file_name()
                        .ok_or_else(|| Error::new(ErrorKind::Other, "文件名称获取错误"))
                        .and_then(|file_name| {
                            file_name
                                .to_str()
                                .ok_or_else(|| Error::new(ErrorKind::Other, "文件名称转换错误"))
                                .map(|s| s.to_string())
                        })
                })
            })
            .collect::<std::result::Result<Vec<String>, Error>>()
    })
}

pub fn build_route_name(file_name: &str) -> Result<String, String> {
    if file_name.is_empty() {
        return Err("File name cannot be empty".to_string());
    }

    let mut result = String::new();
    let mut prev_char_is_upper = false;

    for (i, c) in file_name.chars().enumerate() {
        if i > 0
            && c.is_uppercase()
            && (!prev_char_is_upper
                || (i + 1 < file_name.len()
                    && file_name.chars().nth(i + 1).unwrap().is_lowercase()))
        {
            result.push('_');
        }
        result.push(c.to_ascii_lowercase());
        prev_char_is_upper = c.is_uppercase();
    }

    Ok(result)
}

pub fn get_file_name(file_name: &str) -> String {
    if file_name.ends_with(".vue") {
        file_name.trim_end_matches(".vue").to_string()
    } else {
        file_name.to_string()
    }
}

pub fn build_vue_module(file_name: &str) -> Result<VueModule, String> {
    Ok(VueModule {
        module_name: get_file_name(file_name),
        file_name: file_name.to_string(),
        route_name: build_route_name(&get_file_name(file_name))?,
    })
}

pub fn build_route_content(vue_modules: &Vec<VueModule>) -> String {
    let modules = vue_modules
        .iter()
        .map(|module| {
            format!(
                r#"import {} from "./{}""#,
                module.module_name, module.file_name
            )
        })
        .collect::<Vec<String>>();

    let lines = vue_modules
        .iter()
        .map(|module| {
            format!(
                r#"{{path: "/{}", name: "{}", component: {}}}"#,
                module.route_name, module.route_name, module.module_name
            )
        })
        .collect::<Vec<String>>();

    format!(
        r#"
import {{ createRouter, createWebHistory, RouteRecordRaw }} from "vue-router";
// 导入模块
{}

const routes: Array<RouteRecordRaw> = [
{}
]
;

const router = createRouter({{
  history: createWebHistory(import.meta.env.VITE_BASE_URL),
  routes,
}});

export default router;
        "#,
        modules.join("\n"),
        lines.join("\n")
    )
}

#[test]
fn test_build_route_name() {
    assert_eq!(build_route_name("HomePage").unwrap(), "home_page");
    assert_eq!(build_route_name("homePage").unwrap(), "home_page");
    assert_eq!(
        build_route_name("AdvancedSearchPage").unwrap(),
        "advanced_search_page"
    );
    assert_eq!(
        build_route_name("advancedSearchPage").unwrap(),
        "advanced_search_page"
    );
    assert_eq!(
        build_route_name("MyVeryLongFileName").unwrap(),
        "my_very_long_file_name"
    );
    assert_eq!(
        build_route_name("myVeryLongFileName").unwrap(),
        "my_very_long_file_name"
    );
    assert!(build_route_name("").is_err());
}

#[test]
fn test_get_file_name() {
    assert_eq!(get_file_name("file.vue"), "file");
    assert_eq!(get_file_name("another_file.vue"), "another_file");
    assert_eq!(get_file_name("no_suffix"), "no_suffix");
    assert_eq!(get_file_name("already_trimmed"), "already_trimmed");
}
